home *** CD-ROM | disk | FTP | other *** search
/ OpenGL Superbible (2nd Edition) / OpenGL SuperBible e2.iso / tools / Mesa-3.0 / SRC / SHADE.C < prev    next >
Encoding:
C/C++ Source or Header  |  1998-07-01  |  26.7 KB  |  809 lines

  1. /* $Id: shade.c,v 3.4 1998/07/01 02:39:14 brianp Exp $ */
  2.  
  3. /*
  4.  * Mesa 3-D graphics library
  5.  * Version:  3.0
  6.  * Copyright (C) 1995-1998  Brian Paul
  7.  *
  8.  * This library is free software; you can redistribute it and/or
  9.  * modify it under the terms of the GNU Library General Public
  10.  * License as published by the Free Software Foundation; either
  11.  * version 2 of the License, or (at your option) any later version.
  12.  *
  13.  * This library is distributed in the hope that it will be useful,
  14.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  16.  * Library General Public License for more details.
  17.  *
  18.  * You should have received a copy of the GNU Library General Public
  19.  * License along with this library; if not, write to the Free
  20.  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  21.  */
  22.  
  23.  
  24. /*
  25.  * $Log: shade.c,v $
  26.  * Revision 3.4  1998/07/01 02:39:14  brianp
  27.  * added a hack to work around suspected gcc bug
  28.  *
  29.  * Revision 3.3  1998/04/18 05:00:28  brianp
  30.  * now using FLOAT_COLOR_TO_UBYTE_COLOR macro
  31.  *
  32.  * Revision 3.2  1998/03/27 04:17:31  brianp
  33.  * fixed G++ warnings
  34.  *
  35.  * Revision 3.1  1998/02/02 03:09:34  brianp
  36.  * added GL_LIGHT_MODEL_COLOR_CONTROL (separate specular color interpolation)
  37.  *
  38.  * Revision 3.0  1998/01/31 21:03:42  brianp
  39.  * initial rev
  40.  *
  41.  */
  42.  
  43.  
  44. #ifdef PC_HEADER
  45. #include "all.h"
  46. #else
  47. #include <math.h>
  48. #include "macros.h"
  49. #include "mmath.h"
  50. #include "shade.h"
  51. #include "types.h"
  52. #endif
  53.  
  54.  
  55.  
  56. /*
  57.  * Return x^y.
  58.  */
  59. static GLfloat gl_pow( GLfloat x, GLfloat y )
  60. {
  61.    GLdouble z = pow(x, y);
  62.    if (z<1.0e-10)
  63.       return 0.0F;
  64.    else
  65.       return (GLfloat) z;
  66. }
  67.  
  68.  
  69.  
  70. /*
  71.  * Use current lighting/material settings to compute the RGBA colors of
  72.  * an array of vertexes.
  73.  * Input:  side - 0=use front material, 1=use back material
  74.  *         n - number of vertexes to process
  75.  *         vertex - array of vertex positions in eye coordinates
  76.  *         normal - array of surface normal vectors
  77.  * Output:  color - array of resulting colors
  78.  */
  79. void gl_shade_rgba( GLcontext *ctx,
  80.                     GLuint side,
  81.                     GLuint n,
  82.                     /*const*/ GLfloat vertex[][4],
  83.                     /*const*/ GLfloat normal[][3],
  84.                     GLubyte color[][4] )
  85. {
  86.    GLuint j;
  87.    GLfloat baseR, baseG, baseB, baseA;
  88.    GLint sumA;
  89.    struct gl_light *light;
  90.    struct gl_material *mat;
  91.  
  92.    mat = &ctx->Light.Material[side];
  93.  
  94.    /*** Compute color contribution from global lighting ***/
  95.    baseR = mat->Emission[0] + ctx->Light.Model.Ambient[0] * mat->Ambient[0];
  96.    baseG = mat->Emission[1] + ctx->Light.Model.Ambient[1] * mat->Ambient[1];
  97.    baseB = mat->Emission[2] + ctx->Light.Model.Ambient[2] * mat->Ambient[2];
  98.    baseA = mat->Diffuse[3];  /* Alpha is simple, same for all vertices */
  99.  
  100.    FLOAT_COLOR_TO_UBYTE_COLOR( sumA, baseA );
  101.  
  102.    for (j=0;j<n;j++) {
  103.       GLfloat sumR, sumG, sumB;
  104.       GLfloat nx, ny, nz;
  105.  
  106.       if (side==0) {
  107.          /* shade frontside */
  108.          nx = normal[j][0];
  109.          ny = normal[j][1];
  110.          nz = normal[j][2];
  111.       }
  112.       else {
  113.          /* shade backside */
  114.          nx = -normal[j][0];
  115.          ny = -normal[j][1];
  116.          nz = -normal[j][2];
  117.       }
  118.  
  119.       sumR = baseR;
  120.       sumG = baseG;
  121.       sumB = baseB;
  122.  
  123.       /* Add contribution from each enabled light source */
  124.       for (light=ctx->Light.FirstEnabled; light; light=light->NextEnabled) {
  125.          GLfloat ambientR, ambientG, ambientB;
  126.          GLfloat attenuation, spot;
  127.          GLfloat VPx, VPy, VPz;  /* unit vector from vertex to light */
  128.          GLfloat n_dot_VP;       /* n dot VP */
  129.  
  130.          /* compute VP and attenuation */
  131.          if (light->Position[3]==0.0) {
  132.             /* directional light */
  133.             VPx = light->VP_inf_norm[0];
  134.             VPy = light->VP_inf_norm[1];
  135.             VPz = light->VP_inf_norm[2];
  136.             attenuation = 1.0F;
  137.          }
  138.          else {
  139.             /* positional light */
  140.             GLfloat d;     /* distance from vertex to light */
  141.             VPx = light->Position[0] - vertex[j][0];
  142.             VPy = light->Position[1] - vertex[j][1];
  143.             VPz = light->Position[2] - vertex[j][2];
  144.             d = (GLfloat) GL_SQRT( VPx*VPx + VPy*VPy + VPz*VPz );
  145.             if (d>0.001F) {
  146.                GLfloat invd = 1.0F / d;
  147.                VPx *= invd;
  148.                VPy *= invd;
  149.                VPz *= invd;
  150.             }
  151.             attenuation = 1.0F / (light->ConstantAttenuation
  152.                         + d * (light->LinearAttenuation
  153.                         + d * light->QuadraticAttenuation));
  154.          }
  155.  
  156.          /* spotlight factor */
  157.          if (light->SpotCutoff==180.0F) {
  158.             /* not a spot light */
  159.             spot = 1.0F;
  160.          }
  161.          else {
  162.             GLfloat PVx, PVy, PVz, PV_dot_dir;
  163.             PVx = -VPx;
  164.             PVy = -VPy;
  165.             PVz = -VPz;
  166.             PV_dot_dir = PVx*light->NormDirection[0]
  167.                        + PVy*light->NormDirection[1]
  168.                        + PVz*light->NormDirection[2];
  169.             if (PV_dot_dir<=0.0F || PV_dot_dir<light->CosCutoff) {
  170.                /* outside of cone */
  171.                spot = 0.0F;
  172.             }
  173.             else {
  174.                double x = PV_dot_dir * (EXP_TABLE_SIZE-1);
  175.                int k = (int) x;
  176.                spot = light->SpotExpTable[k][0]
  177.                     + (x-k)*light->SpotExpTable[k][1];
  178.             }
  179.          }
  180.  
  181.          ambientR = mat->Ambient[0] * light->Ambient[0];
  182.          ambientG = mat->Ambient[1] * light->Ambient[1];
  183.          ambientB = mat->Ambient[2] * light->Ambient[2];
  184.  
  185.          /* Compute dot product or normal and vector from V to light pos */
  186.          n_dot_VP = nx * VPx + ny * VPy + nz * VPz;
  187.  
  188.          /* diffuse and specular terms */
  189.          if (n_dot_VP<=0.0F) {
  190.             /* surface face away from light, no diffuse or specular */
  191.             GLfloat t = attenuation * spot;
  192.             sumR += t * ambientR;
  193.             sumG += t * ambientG;
  194.             sumB += t * ambientB;
  195.             /* done with this light */
  196.          }
  197.          else {
  198.             GLfloat diffuseR, diffuseG, diffuseB;
  199.             GLfloat specularR, specularG, specularB;
  200.             GLfloat h_x, h_y, h_z, n_dot_h, t;
  201.                   
  202.             /* diffuse term */
  203.             diffuseR = n_dot_VP * mat->Diffuse[0] * light->Diffuse[0];
  204.             diffuseG = n_dot_VP * mat->Diffuse[1] * light->Diffuse[1];
  205.             diffuseB = n_dot_VP * mat->Diffuse[2] * light->Diffuse[2];
  206.  
  207.             /* specular term */
  208.             if (ctx->Light.Model.LocalViewer) {
  209.                GLfloat vx, vy, vz, vlen;
  210.                vx = vertex[j][0];
  211.                vy = vertex[j][1];
  212.                vz = vertex[j][2];
  213.                vlen = GL_SQRT( vx*vx + vy*vy + vz*vz );
  214.                if (vlen>0.0001F) {
  215.                   GLfloat invlen = 1.0F / vlen;
  216.                   vx *= invlen;
  217.                   vy *= invlen;
  218.                   vz *= invlen;
  219.                }
  220.                /* h = VP + VPe */
  221.                h_x = VPx - vx;
  222.                h_y = VPy - vy;
  223.                h_z = VPz - vz;
  224.             }
  225.             else {
  226.                /* h = VP + <0,0,1> */
  227.                h_x = VPx;
  228.                h_y = VPy;
  229.                h_z = VPz + 1.0F;
  230.             }
  231.  
  232.             /* attention: h is not normalized, done later if needed */
  233.             n_dot_h = nx*h_x + ny*h_y + nz*h_z;
  234.  
  235.             if (n_dot_h<=0.0F) {
  236.                specularR = 0.0F;
  237.                specularG = 0.0F;
  238.                specularB = 0.0F;
  239.             }
  240.             else {
  241.                GLfloat spec_coef;
  242.                /* now `correct' the dot product */
  243.                n_dot_h = n_dot_h / GL_SQRT( h_x*h_x + h_y*h_y + h_z*h_z );
  244.                if (n_dot_h>1.0F) {
  245.                   /* only happens if normal vector length > 1.0 */
  246.                   spec_coef = pow( n_dot_h, mat->Shininess );
  247.                }
  248.                else {
  249.                   /* use table lookup approximation */
  250.                   int k = (int) (n_dot_h * (GLfloat) (SHINE_TABLE_SIZE-1));
  251.                   if (mat->ShineTable[k] < 0.0F)
  252.                      mat->ShineTable[k] = gl_pow( n_dot_h, mat->Shininess );
  253.                   spec_coef = mat->ShineTable[k];
  254.                }
  255.                if (spec_coef<1.0e-10) {
  256.                   specularR = 0.0F;
  257.                   specularG = 0.0F;
  258.                   specularB = 0.0F;
  259.                }
  260.                else {
  261.                   specularR = spec_coef * mat->Specular[0]*light->Specular[0];
  262.                   specularG = spec_coef * mat->Specular[1]*light->Specular[1];
  263.                   specularB = spec_coef * mat->Specular[2]*light->Specular[2];
  264.                }
  265.             }
  266.  
  267.             t = attenuation * spot;
  268.             sumR += t * (ambientR + diffuseR + specularR);
  269.             sumG += t * (ambientG + diffuseG + specularG);
  270.             sumB += t * (ambientB + diffuseB + specularB);
  271.          }
  272.  
  273.       } /*loop over lights*/
  274.  
  275.       /* clamp and convert to integer or fixed point */
  276.       FLOAT_COLOR_TO_UBYTE_COLOR( color[j][0], sumR );
  277.       FLOAT_COLOR_TO_UBYTE_COLOR( color[j][1], sumG );
  278.       FLOAT_COLOR_TO_UBYTE_COLOR( color[j][2], sumB );
  279.       color[j][3] = sumA;
  280.  
  281.    } /*loop over vertices*/
  282. }
  283.  
  284.  
  285.  
  286. /*
  287.  * Compute separate base and specular colors.
  288.  * Input:  side - 0=use front material, 1=use back material
  289.  *         n - number of vertexes to process
  290.  *         vertex - array of vertex positions in eye coordinates
  291.  *         normal - array of surface normal vectors
  292.  * Output:  baseColor - array of base colors (emission, ambient, diffuse)
  293.  *          specColor - array of specular colors
  294.  */
  295. void gl_shade_rgba_spec( GLcontext *ctx,
  296.                          GLuint side,
  297.                          GLuint n,
  298.                          /*const*/ GLfloat vertex[][4],
  299.                          /*const*/ GLfloat normal[][3],
  300.                          GLubyte baseColor[][4], GLubyte specColor[][4] )
  301. {
  302.    GLuint j;
  303.    GLfloat baseR, baseG, baseB, baseA;
  304.    GLint sumBaseA;
  305.    struct gl_light *light;
  306.    struct gl_material *mat;
  307.  
  308.    mat = &ctx->Light.Material[side];
  309.  
  310.    /*** Compute color contribution from global lighting ***/
  311.    baseR = mat->Emission[0] + ctx->Light.Model.Ambient[0] * mat->Ambient[0];
  312.    baseG = mat->Emission[1] + ctx->Light.Model.Ambient[1] * mat->Ambient[1];
  313.    baseB = mat->Emission[2] + ctx->Light.Model.Ambient[2] * mat->Ambient[2];
  314.    baseA = mat->Diffuse[3];  /* Alpha is simple, same for all vertices */
  315.  
  316.    FLOAT_COLOR_TO_UBYTE_COLOR( sumBaseA, baseA );
  317.  
  318.    for (j=0;j<n;j++) {
  319.       GLfloat sumBaseR, sumBaseG, sumBaseB;
  320.       GLfloat sumSpecR, sumSpecG, sumSpecB;
  321.       GLfloat nx, ny, nz;
  322.  
  323.       if (side==0) {
  324.          /* shade frontside */
  325.          nx = normal[j][0];
  326.          ny = normal[j][1];
  327.          nz = normal[j][2];
  328.       }
  329.       else {
  330.          /* shade backside */
  331.          nx = -normal[j][0];
  332.          ny = -normal[j][1];
  333.          nz = -normal[j][2];
  334.       }
  335.  
  336.       sumBaseR = baseR;
  337.       sumBaseG = baseG;
  338.       sumBaseB = baseB;
  339.       sumSpecR = sumSpecG = sumSpecB = 0.0;
  340.  
  341.       /* Add contribution from each enabled light source */
  342.       for (light=ctx->Light.FirstEnabled; light; light=light->NextEnabled) {
  343.          GLfloat ambientR, ambientG, ambientB;
  344.          GLfloat attenuation, spot;
  345.          GLfloat VPx, VPy, VPz;  /* unit vector from vertex to light */
  346.          GLfloat n_dot_VP;       /* n dot VP */
  347.  
  348.          /* compute VP and attenuation */
  349.          if (light->Position[3]==0.0) {
  350.             /* directional light */
  351.             VPx = light->VP_inf_norm[0];
  352.             VPy = light->VP_inf_norm[1];
  353.             VPz = light->VP_inf_norm[2];
  354.             attenuation = 1.0F;
  355.          }
  356.          else {
  357.             /* positional light */
  358.             GLfloat d;     /* distance from vertex to light */
  359.             VPx = light->Position[0] - vertex[j][0];
  360.             VPy = light->Position[1] - vertex[j][1];
  361.             VPz = light->Position[2] - vertex[j][2];
  362.             d = (GLfloat) GL_SQRT( VPx*VPx + VPy*VPy + VPz*VPz );
  363.             if (d>0.001F) {
  364.                GLfloat invd = 1.0F / d;
  365.                VPx *= invd;
  366.                VPy *= invd;
  367.                VPz *= invd;
  368.             }
  369.             attenuation = 1.0F / (light->ConstantAttenuation
  370.                         + d * (light->LinearAttenuation
  371.                         + d * light->QuadraticAttenuation));
  372.          }
  373.  
  374.          /* spotlight factor */
  375.          if (light->SpotCutoff==180.0F) {
  376.             /* not a spot light */
  377.             spot = 1.0F;
  378.          }
  379.          else {
  380.             GLfloat PVx, PVy, PVz, PV_dot_dir;
  381.             PVx = -VPx;
  382.             PVy = -VPy;
  383.             PVz = -VPz;
  384.             PV_dot_dir = PVx*light->NormDirection[0]
  385.                        + PVy*light->NormDirection[1]
  386.                        + PVz*light->NormDirection[2];
  387.             if (PV_dot_dir<=0.0F || PV_dot_dir<light->CosCutoff) {
  388.                /* outside of cone */
  389.                spot = 0.0F;
  390.             }
  391.             else {
  392.                double x = PV_dot_dir * (EXP_TABLE_SIZE-1);
  393.                int k = (int) x;
  394.                spot = light->SpotExpTable[k][0]
  395.                     + (x-k)*light->SpotExpTable[k][1];
  396.             }
  397.          }
  398.  
  399.          ambientR = mat->Ambient[0] * light->Ambient[0];
  400.          ambientG = mat->Ambient[1] * light->Ambient[1];
  401.          ambientB = mat->Ambient[2] * light->Ambient[2];
  402.  
  403.          /* Compute dot product or normal and vector from V to light pos */
  404.          n_dot_VP = nx * VPx + ny * VPy + nz * VPz;
  405.  
  406.          /* diffuse and specular terms */
  407.          if (n_dot_VP<=0.0F) {
  408.             /* surface face away from light, no diffuse or specular */
  409.             GLfloat t = attenuation * spot;
  410.             sumBaseR += t * ambientR;
  411.             sumBaseG += t * ambientG;
  412.             sumBaseB += t * ambientB;
  413.             /* done with this light */
  414.          }
  415.          else {
  416.             GLfloat diffuseR, diffuseG, diffuseB;
  417.             GLfloat specularR, specularG, specularB;
  418.             GLfloat h_x, h_y, h_z, n_dot_h, t;
  419.                   
  420.             /* diffuse term */
  421.             diffuseR = n_dot_VP * mat->Diffuse[0] * light->Diffuse[0];
  422.             diffuseG = n_dot_VP * mat->Diffuse[1] * light->Diffuse[1];
  423.             diffuseB = n_dot_VP * mat->Diffuse[2] * light->Diffuse[2];
  424.  
  425.             /* specular term */
  426.             if (ctx->Light.Model.LocalViewer) {
  427.                GLfloat vx, vy, vz, vlen;
  428.                vx = vertex[j][0];
  429.                vy = vertex[j][1];
  430.                vz = vertex[j][2];
  431.                vlen = GL_SQRT( vx*vx + vy*vy + vz*vz );
  432.                if (vlen>0.0001F) {
  433.                   GLfloat invlen = 1.0F / vlen;
  434.                   vx *= invlen;
  435.                   vy *= invlen;
  436.                   vz *= invlen;
  437.                }
  438.                /* h = VP + VPe */
  439.                h_x = VPx - vx;
  440.                h_y = VPy - vy;
  441.                h_z = VPz - vz;
  442.             }
  443.             else {
  444.                /* h = VP + <0,0,1> */
  445.                h_x = VPx;
  446.                h_y = VPy;
  447.                h_z = VPz + 1.0F;
  448.             }
  449.  
  450.             /* attention: h is not normalized, done later if needed */
  451.             n_dot_h = nx*h_x + ny*h_y + nz*h_z;
  452.  
  453.             if (n_dot_h<=0.0F) {
  454.                specularR = 0.0F;
  455.                specularG = 0.0F;
  456.                specularB = 0.0F;
  457.             }
  458.             else {
  459.                GLfloat spec_coef;
  460.                /* now `correct' the dot product */
  461.                n_dot_h = n_dot_h / GL_SQRT( h_x*h_x + h_y*h_y + h_z*h_z );
  462.                if (n_dot_h>1.0F) {
  463.                   /* only happens if normal vector length > 1.0 */
  464.                   spec_coef = pow( n_dot_h, mat->Shininess );
  465.                }
  466.                else {
  467.                   /* use table lookup approximation */
  468.                   int k = (int) (n_dot_h * (GLfloat) (SHINE_TABLE_SIZE-1));
  469.                   if (mat->ShineTable[k] < 0.0F)
  470.                      mat->ShineTable[k] = gl_pow( n_dot_h, mat->Shininess );
  471.                   spec_coef = mat->ShineTable[k];
  472.                }
  473.                if (spec_coef<1.0e-10) {
  474.                   specularR = 0.0F;
  475.                   specularG = 0.0F;
  476.                   specularB = 0.0F;
  477.                }
  478.                else {
  479.                   specularR = spec_coef * mat->Specular[0]*light->Specular[0];
  480.                   specularG = spec_coef * mat->Specular[1]*light->Specular[1];
  481.                   specularB = spec_coef * mat->Specular[2]*light->Specular[2];
  482.                }
  483.             }
  484.  
  485.             t = attenuation * spot;
  486.             sumBaseR += t * (ambientR + diffuseR);
  487.             sumBaseG += t * (ambientG + diffuseG);
  488.             sumBaseB += t * (ambientB + diffuseB);
  489.             sumSpecR += t * specularR;
  490.             sumSpecG += t * specularG;
  491.             sumSpecB += t * specularB;
  492.          }
  493.  
  494.       } /*loop over lights*/
  495.  
  496.       /* clamp and convert to integer or fixed point */
  497.       FLOAT_COLOR_TO_UBYTE_COLOR( baseColor[j][0], sumBaseR );
  498.       FLOAT_COLOR_TO_UBYTE_COLOR( baseColor[j][1], sumBaseG );
  499.       FLOAT_COLOR_TO_UBYTE_COLOR( baseColor[j][2], sumBaseB );
  500.       baseColor[j][3] = sumBaseA;
  501.  
  502.       FLOAT_COLOR_TO_UBYTE_COLOR( specColor[j][0], sumSpecR );
  503.       FLOAT_COLOR_TO_UBYTE_COLOR( specColor[j][1], sumSpecG );
  504.       FLOAT_COLOR_TO_UBYTE_COLOR( specColor[j][2], sumSpecB );
  505.       specColor[j][3] = 255;  /* but never used */
  506.  
  507.    } /*loop over vertices*/
  508. }
  509.  
  510.  
  511.  
  512. /*
  513.  * This is an optimized version of the above function.
  514.  */
  515. void gl_shade_rgba_fast( GLcontext *ctx,
  516.                          GLuint side,
  517.                          GLuint n,
  518.                          /*const*/ GLfloat normal[][3],
  519.                          GLubyte color[][4] )
  520. {
  521.    GLuint j;
  522.    GLint sumA;
  523.    GLfloat *baseColor = ctx->Light.BaseColor[side];
  524.  
  525.    /* Alpha is easy to compute, same for all vertices */
  526.    sumA = (GLint) (baseColor[3] * 255.0F);
  527.  
  528.    /* Loop over vertices */
  529.    for (j=0;j<n;j++) {
  530.       GLfloat sumR, sumG, sumB;
  531.       GLfloat nx, ny, nz;
  532.       struct gl_light *light;
  533.  
  534.       /* the normal vector */
  535.       if (side==0) {
  536.          nx = normal[j][0];
  537.          ny = normal[j][1];
  538.          nz = normal[j][2];
  539.       }
  540.       else {
  541.          nx = -normal[j][0];
  542.          ny = -normal[j][1];
  543.          nz = -normal[j][2];
  544.       }
  545.  
  546. #ifdef SPEED_HACK
  547.       if (nz<0.0F) {
  548.          color[j][0] = 0.0F;
  549.          color[j][1] = 0.0F;
  550.          color[j][2] = 0.0F;
  551.          color[j][3] = A;
  552.          continue;
  553.       }
  554. #endif
  555.  
  556.       /* base color from global illumination and enabled light's ambient */
  557.       sumR = baseColor[0];
  558.       sumG = baseColor[1];
  559.       sumB = baseColor[2];
  560.  
  561.       /* Add contribution from each light source */
  562.       for (light=ctx->Light.FirstEnabled; light; light=light->NextEnabled) {
  563.          GLfloat n_dot_VP;     /* n dot VP */
  564.  
  565.          n_dot_VP = nx * light->VP_inf_norm[0]
  566.                   + ny * light->VP_inf_norm[1]
  567.                   + nz * light->VP_inf_norm[2];
  568.  
  569.          /* diffuse and specular terms */
  570.          if (n_dot_VP>0.0F) {
  571.             GLfloat n_dot_h;
  572.             GLfloat *lightMatDiffuse = light->MatDiffuse[side];
  573.  
  574.             /** add diffuse term **/
  575.             sumR += n_dot_VP * lightMatDiffuse[0];
  576.             sumG += n_dot_VP * lightMatDiffuse[1];
  577.             sumB += n_dot_VP * lightMatDiffuse[2];
  578.  
  579.             /** specular term **/
  580.             /* dot product of n and h_inf_norm */
  581.             n_dot_h = nx * light->h_inf_norm[0]
  582.                     + ny * light->h_inf_norm[1]
  583.                     + nz * light->h_inf_norm[2];
  584.             if (n_dot_h>0.0F) {
  585.                if (n_dot_h>1.0F) {
  586.                   /* only happens if Magnitude(n) > 1.0 */
  587.                   GLfloat spec_coef = pow( n_dot_h,
  588.                                         ctx->Light.Material[side].Shininess );
  589.                   if (spec_coef>1.0e-10F) {
  590.                      sumR += spec_coef * light->MatSpecular[side][0];
  591.                      sumG += spec_coef * light->MatSpecular[side][1];
  592.                      sumB += spec_coef * light->MatSpecular[side][2];
  593.                   }
  594.                }
  595.                else {
  596.                   /* use table lookup approximation */
  597.                   int k = (int) (n_dot_h * (GLfloat) (SHINE_TABLE_SIZE-1));
  598.                   struct gl_material *m = &ctx->Light.Material[side];
  599.                   GLfloat spec_coef;
  600.                   if (m->ShineTable[k] < 0.0F)
  601.                      m->ShineTable[k] = gl_pow( n_dot_h, m->Shininess );
  602.                   spec_coef = m->ShineTable[k];
  603.                   sumR += spec_coef * light->MatSpecular[side][0];
  604.                   sumG += spec_coef * light->MatSpecular[side][1];
  605.                   sumB += spec_coef * light->MatSpecular[side][2];
  606.                }
  607.             }
  608.          }
  609.  
  610.       } /*loop over lights*/
  611.  
  612.       /* clamp and convert to integer or fixed point */
  613.       FLOAT_COLOR_TO_UBYTE_COLOR( color[j][0], sumR );
  614.       FLOAT_COLOR_TO_UBYTE_COLOR( color[j][1], sumG );
  615.       FLOAT_COLOR_TO_UBYTE_COLOR( color[j][2], sumB );
  616.       color[j][3] = sumA;
  617.  
  618.       /* Ugh, I think there's a bug in gcc 2.7.2.3.  If the following
  619.        * no-op code isn't here then the results of the above
  620.        * FLOAT_COLOR_TO_UBYTE_COLOR() macro are unpredictable!
  621.        */
  622.       {
  623.          GLubyte r0 = FloatToInt(CLAMP(sumR, 0, 1) * 255.0);
  624.       }
  625.  
  626.    } /*loop over vertices*/
  627. }
  628.  
  629.  
  630.  
  631. /*
  632.  * Use current lighting/material settings to compute the color indexes
  633.  * for an array of vertices.
  634.  * Input:  n - number of vertices to shade
  635.  *         side - 0=use front material, 1=use back material
  636.  *         vertex - array of [n] vertex position in eye coordinates
  637.  *         normal - array of [n] surface normal vector
  638.  * Output:  indexResult - resulting array of [n] color indexes
  639.  */
  640. void gl_shade_ci( GLcontext *ctx,
  641.                   GLuint side,
  642.                   GLuint n,
  643.                   GLfloat vertex[][4],
  644.                   GLfloat normal[][3],
  645.                   GLuint indexResult[] )
  646. {
  647.    struct gl_material *mat = &ctx->Light.Material[side];
  648.    GLuint j;
  649.  
  650.    /* loop over vertices */
  651.    for (j=0;j<n;j++) {
  652.       GLfloat index;
  653.       GLfloat diffuse, specular;  /* accumulated diffuse and specular */
  654.       GLfloat nx, ny, nz;  /* normal vector */
  655.       struct gl_light *light;
  656.  
  657.       if (side==0) {
  658.          /* shade frontside */
  659.          nx = normal[j][0];
  660.          ny = normal[j][1];
  661.          nz = normal[j][2];
  662.       }
  663.       else {
  664.          /* shade backside */
  665.          nx = -normal[j][0];
  666.          ny = -normal[j][1];
  667.          nz = -normal[j][2];
  668.       }
  669.  
  670.       diffuse = specular = 0.0F;
  671.  
  672.       /* Accumulate diffuse and specular from each light source */
  673.       for (light=ctx->Light.FirstEnabled; light; light=light->NextEnabled) {
  674.          GLfloat attenuation;
  675.          GLfloat lx, ly, lz;  /* unit vector from vertex to light */
  676.          GLfloat l_dot_norm;  /* dot product of l and n */
  677.  
  678.          /* compute l and attenuation */
  679.          if (light->Position[3]==0.0) {
  680.             /* directional light */
  681.             /* Effectively, l is a vector from the origin to the light. */
  682.             lx = light->VP_inf_norm[0];
  683.             ly = light->VP_inf_norm[1];
  684.             lz = light->VP_inf_norm[2];
  685.             attenuation = 1.0F;
  686.          }
  687.          else {
  688.             /* positional light */
  689.             GLfloat d;     /* distance from vertex to light */
  690.             lx = light->Position[0] - vertex[j][0];
  691.             ly = light->Position[1] - vertex[j][1];
  692.             lz = light->Position[2] - vertex[j][2];
  693.             d = (GLfloat) GL_SQRT( lx*lx + ly*ly + lz*lz );
  694.             if (d>0.001F) {
  695.                GLfloat invd = 1.0F / d;
  696.                lx *= invd;
  697.                ly *= invd;
  698.                lz *= invd;
  699.             }
  700.             attenuation = 1.0F / (light->ConstantAttenuation
  701.                         + d * (light->LinearAttenuation
  702.                         + d * light->QuadraticAttenuation));
  703.          }
  704.  
  705.          l_dot_norm = lx*nx + ly*ny + lz*nz;
  706.  
  707.          if (l_dot_norm>0.0F) {
  708.             GLfloat spot_times_atten;
  709.  
  710.             /* spotlight factor */
  711.             if (light->SpotCutoff==180.0F) {
  712.                /* not a spot light */
  713.                spot_times_atten = attenuation;
  714.             }
  715.             else {
  716.                GLfloat v[3], dot;
  717.                v[0] = -lx;  /* v points from light to vertex */
  718.                v[1] = -ly;
  719.                v[2] = -lz;
  720.                dot = DOT3( v, light->NormDirection );
  721.                if (dot<=0.0F || dot<light->CosCutoff) {
  722.                   /* outside of cone */
  723.                   spot_times_atten = 0.0F;
  724.                }
  725.                else {
  726.                   double x = dot * (EXP_TABLE_SIZE-1);
  727.                   int k = (int) x;
  728.                   GLfloat spot = light->SpotExpTable[k][0]
  729.                                + (x-k)*light->SpotExpTable[k][1];
  730.                   spot_times_atten = spot * attenuation;
  731.                }
  732.             }
  733.  
  734.             /* accumulate diffuse term */
  735.             diffuse += l_dot_norm * light->dli * spot_times_atten;
  736.  
  737.             /* accumulate specular term */
  738.             {
  739.                GLfloat h_x, h_y, h_z, n_dot_h, spec_coef;
  740.  
  741.                /* specular term */
  742.                if (ctx->Light.Model.LocalViewer) {
  743.                   GLfloat vx, vy, vz, vlen;
  744.                   vx = vertex[j][0];
  745.                   vy = vertex[j][1];
  746.                   vz = vertex[j][2];
  747.                   vlen = GL_SQRT( vx*vx + vy*vy + vz*vz );
  748.                   if (vlen>0.0001F) {
  749.                      GLfloat invlen = 1.0F / vlen;
  750.                      vx *= invlen;
  751.                      vy *= invlen;
  752.                      vz *= invlen;
  753.                   }
  754.                   h_x = lx - vx;
  755.                   h_y = ly - vy;
  756.                   h_z = lz - vz;
  757.                }
  758.                else {
  759.                   h_x = lx;
  760.                   h_y = ly;
  761.                   h_z = lz + 1.0F;
  762.                }
  763.                /* attention: s is not normalized, done later if necessary */
  764.                n_dot_h = h_x*nx + h_y*ny + h_z*nz;
  765.  
  766.                if (n_dot_h <= 0.0F) {
  767.                   spec_coef = 0.0F;
  768.                }
  769.                else {
  770.                   /* now `correct' the dot product */
  771.                   n_dot_h = n_dot_h / GL_SQRT(h_x*h_x + h_y*h_y + h_z*h_z);
  772.                   if (n_dot_h>1.0F) {
  773.                      spec_coef = pow( n_dot_h, mat->Shininess );
  774.                   }
  775.                   else {
  776.                      int k = (int) (n_dot_h * (GLfloat)(SHINE_TABLE_SIZE-1));
  777.                      if (mat->ShineTable[k] < 0.0F)
  778.                         mat->ShineTable[k] = gl_pow( n_dot_h, mat->Shininess );
  779.                      spec_coef = mat->ShineTable[k];
  780.                   }
  781.                }
  782.                specular += spec_coef * light->sli * spot_times_atten;
  783.             }
  784.          }
  785.  
  786.       } /*loop over lights*/
  787.  
  788.       /* Now compute final color index */
  789.       if (specular>1.0F) {
  790.          index = mat->SpecularIndex;
  791.       }
  792.       else {
  793.          GLfloat d_a, s_a;
  794.          d_a = mat->DiffuseIndex - mat->AmbientIndex;
  795.          s_a = mat->SpecularIndex - mat->AmbientIndex;
  796.  
  797.          index = mat->AmbientIndex
  798.                + diffuse * (1.0F-specular) * d_a
  799.                + specular * s_a;
  800.          if (index>mat->SpecularIndex) {
  801.             index = mat->SpecularIndex;
  802.          }
  803.       }
  804.       indexResult[j] = (GLuint) (GLint) index;
  805.  
  806.    } /*for vertex*/
  807. }
  808.  
  809.